home *** CD-ROM | disk | FTP | other *** search
Text File | 1999-05-17 | 70.2 KB | 2,244 lines | [TEXT/MPS ] |
- /*
- File: FWSBP2DiskDriver.c
-
- Contains: Sample SBP-2 Hard Disk driver
-
- Version: 1.0
-
- Copyright: © 1998-1999 by Apple Computer, Inc., all rights reserved.
-
- File Ownership:
-
- DRI: Clinton Bauder
-
- Other Contact: Eric Anderson
-
- Technology: FireWire
-
- Writers:
-
- (EA) Eric Anderson (ewa)
- (DCB) Clinton Bauder
-
- Change History (most recent first):
-
- <FW42> 5/4/99 DCB Clear the gpFWSBP2DriverData->loginObjBusy variable if we fail
- find a drive when we go looking for it. This fixes the problem
- where a drive doesn't re-mount after being dragged to the trash.
- <FW41> 4/30/99 EA Changed to protect the LUN reset object from being used when it
- is already in use.
- <FW40> 4/29/99 DCB Fixed a problem with the lookfordrive function which was
- re-using the login command object when it shouldn't be. Now it
- uses the loginObjBusy variable to protect both the login object
- and the CSR read object from premature re-use. Also added code
- to not retry requests if we get ORB status while in the midst of
- logging in or reconnecting. Sometimes we get called with
- notification twice for the same ORB after a reset. This prevents
- us from trying to use the Management Agent to reset the LUN or
- do other error recovery until we're sure we're logged in again.
- <FW39> 4/29/99 EA Changed to restore BUSY_TIMEOUT after each login or reconnect.
- <FW38> 4/24/99 EA Changed FWSetRetryResponseOnAckDataErr to FWSetFWDeviceFlags.
- Also changed to set kFWDeviceDoNotEjectCardBus flag while we
- have a volume (possibly) mounted.
- <FW37> 4/22/99 DCB Add a missing break to the main dispatch loop. Mostly for
- neatness. Doesn't change the generated code.
- <FW36> 4/17/99 DCB Don't unilaterally return statusErr from the status routine.
- Return the real error if any. Get rid of non-functional ROM
- flashing code. Call IOCommandIsComplete if we get an error from
- readwriteblocks so we don't hang. Fixed a "flashing dialog"
- problem for wall powered devices caused by improper handling of
- login failed notifications.
- <FW35> 3/31/99 EA Added call to FWSetRetryResponseOnAckDataErr for better
- performance.
- <FW34> 3/27/99 EA Changed descriptor back to sbp609e,104d8 (from sbp0,0).
- <FW33> 3/27/99 EA Changed to use aligned double-buffer for any request of 8K or
- less.
- <FW32> 3/15/99 DCB Mask the incoming buffer with 0x0000000F instead of 0x00000007
- when deciding to double buffer as some devices have trouble with
- the smaller alignment restriction.
- <FW31> 3/8/99 DCB Lengthen the timeout for TURs to 5 seconds. Some devices don't
- like a LUNReset command while a TUR is still active.
- <FW30> 3/8/99 DCB Slight improvement in the way we handle ReadCapacity commands.
- Some devices after a crash can get into a state where the return
- good status for this command but don't actually send us any
- data. Now if we don't get a valid capacity we return an error up
- the chain and don't load the driver. I'm investigating ways to
- reset the drive to fix the problem for real but this is better
- than creating a bogus drive queue element and risking erasing
- the volume.
- <FW29> 3/8/99 DCB And one more change. Changed the TheDFMDescriptor ranges for
- VendorID and SoftwareRev to "don't care" from "match
- everything". This makes it easier for "real" drivers with more
- specific DFMDescriptors to override this driver.
- <FW28> 3/8/99 DCB Lots of cleanup and some real improvements too. Now if
- needLUNReset is set true in the header file we use the
- FWSBP2Manage function to reset the LUN before resetting the
- fetch agent. Allows us to recover from bad packets on devices
- that don't always respond to a fetch agent reset (you know who
- you are...). Also cleaned up the state variables for keeping
- track of logins. Now logout on eject control call to spin down
- the disk. Also make sure we're done logging out before
- de-allocating the login ORB if our initial login failed.
- <FW27> 3/4/99 DCB Two things: Fixed a performance issue with double buffering for
- reads. We were blockmoving the size of the whole buffer for each
- chunk, not the chunk size. Second add support for verifying
- writes. Sorry about the clutter but it is pretty useful for
- tracking down data corruption problems.
- <FW26> 3/2/99 DCB Add support for a bunch of DriverGestalt calls. Also now if we
- get login failed notification we try to login again on the
- assumption that we were unplugged or reset during a login.
- <FW25> 2/15/99 DCB Add better support for 2 macs-1 drive, that is do the right
- thing if we fail a login.
- <FW24> 2/15/99 DCB Add support for Eric's notification changes. Basically now we
- assume ORBs are canceled immediately following a reset. Also
- don't bother paying attention to resets if we are waiting for a
- re-plug. Let FSL do that for us.
- <FW23> 2/12/99 EA Changed max payload size to 256 for now.
- <FW22> 2/8/99 DCB Make the DFMDescriptor and DriverDescriptor more correct (and
- specific).
- <FW21> 1/25/99 DCB Misc. Cleanup of the re-plug code. Handle loginFailed responses
- better. Try to prevent re-entrant us of resources related to
- logging in after the reconnect timeout fails.
- <FW20> 1/21/99 DCB Clear the gotEject flag on a login so we know the drive is
- around and don't inadvertently return errors.
- <FW19> 1/21/99 DCB Cleaned up the hot-unplugging code to get rid of the unnecessary
- DeviceNotify stuff and use instead the brand new
- FWWaitForDeviceRePlug() API I just invented. Now we get a DSAT
- warning if the drive goes away unexpectedly. If the user cancels
- this with Command-. we start returning ioErr until the drive
- returns.
- <FW18> 1/19/99 EA Fixed FlashSymbiosROM to set the generation value so that the
- flag kFWAsynchFailOnBusReset will work as intended.
- <FW17> 1/19/99 DCB Clean up some comments and the Finalize routine (still never
- called but it should at least show what should be done).
- <FW16> 1/19/99 DCB Did a couple of things. First we now nearly always recover from
- a hot unplug followed by a re-plug. Occasionally we don't get
- ORB notification for an outstanding ORB if the re-plug happens
- before the reconnect fails. Unplugging and replugging again
- fixes this. The bug appears to be in FSL. I also added a boolean
- in the eject code which we use to keep track of whether the disk
- has been unmounted. If so we post a diskEvt every time we login.
- This way the drive re-appears when re-plugged after being
- unmounted and unplugged. User dialogs asking for a disk to be
- inserted when hot unplugged while a volume is mounted are not
- implemented yet. Stay tuned.
- <FW15> 1/15/99 EA Changed to set the BUSY_TIMEOUT register in the drive so that it
- will retry busy packets. This works (helps?) on the LSI Native
- Bridge. Removed kFWCommandSyncFlag from asynch command flags
- (it is a plain command flag, and those are different). Gave
- FlashSymbiosROM its own command object but did not test this as
- I have no card to flash.
- <FW14> 1/15/99 DCB Don't return an error from eject. This allows us to unmount the
- drive before unplugging it without getting an annoying error
- from the finder.
- <FW13> 1/15/99 DCB Nearly almost have hot-unplugging and re-plugging working. See
- my comment block in the device notification section for details
- on why it doesn't _quite_ work yet.
- <FW12> 1/3/99 EA Changed to set kSBP2CommandNormalORB flag for normal ORBs.
- <FW11> 12/31/98 EA Changed to pre-allocate 12288 bytes of storage for each normal
- command object, as per the latest SBP-2 API document.
- <FW10> 12/29/98 DCB Double buffer requests if the buffer passed in from the OS is
- not aligned to a cache line. SBP is unclear on whether this is
- required but some devices clearly need it.
- <FW9> 12/23/98 DCB Don't do ReqSense anymore as some drives don't like this. Back
- to straight retries for error checking. Also fixed up the
- Symbios ROM flash code.
- <FW8> 12/19/98 DCB Minor cleanup of the sample Symbios ROM and ATA mode code at the
- end of this file.
- <FW7> 12/18/98 DCB Make sure we wait for login before trying to use the fetch
- agent.
- <FW6> 12/18/98 DCB Fix some things up for native bridge support. Make request sense
- calls now when fetch agent goes dead. Much better threading and
- error recovery when we write to the fetch agent's reset
- register.
- <FW5> 12/7/98 EA Removed brand name from comment.
- <FW4> 12/1/98 EA Changed to set maximum payload size to 512 in login command
- object (default is 4, but it wasn't previously enforced).
- <FW3> 11/20/98 DCB Use Eric's new API to decide which ORB we just got notification
- for. Also clean up some comments.
- <FW2> 11/17/98 DCB Misc Cleanup.
- <FW1> 11/17/98 DCB first checked in
- <FW3> 10/28/98 DCB Using new defs for matching SBP drivers. This allows us to be
- much more specific in our decision as to which driver belongs to
- which device.
- <FW2> 9/20/98 EA Filled in header comments.
- <FW1> 9/20/98 EA first checked in
- */
-
-
- #include <Types.h>
- #include <Files.h>
- #include <Errors.h>
- #include <Disks.h>
- #include <DriverGestalt.h>
- #include <OSUtils.h>
- #include <Devices.h>
- #include <DriverServices.h>
- #include <LowMem.h>
- #include <FireWire.h>
- #include <FireWireSBP2.h>
- #include <SampleSBP2.h>
- #include <FWSBP2DiskDriver.h>
- /*zzz*/
- #include <TextUtils.h>
- #include <stdio.h>
- char debugStr[256];
- /*zzz*/
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Notes and Caveats
- //
- // This is an example of how to use SPB rather than an example of a complete
- // hard disk driver. It is, in fact, a long way from being a shipping product
- // and should be viewed as such.
- //
- // This driver uses the whole hard disk and doesn't understand partitions.
- //
- // Support for immediate calls is suspect at best.
- //
- // Error handling consists entirely of retries no matter what went wrong.
- //
- // DriverGestalt call support is a bit minimal (but better than what it was).
- //
- // The DFMDescriptor in this file is quite imprecise and will install this driver
- // on a wide variety of devices.
- //
- // This driver makes no attempt to manage or handle bus power. It should use
- // the power APIs in FireWire 2.0 to ask if there is enough power to spin up
- // the drive before logging in (assuming the drive is bus powered).
- //
- // No attempt is made to provide exclusive access to one client save the normal
- // SBP2 login. Which mac gets a drive after it shows up on a local FireWire net
- // is strictly first come first serve. This is true even after a re-plug when one
- // of the Macs might have a volume mounted. In this case if another Mac gets the
- // login bad things will happen.
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Internal procedure prototypes.
- //
-
- OSErr DoDriverIO(
- AddressSpaceID addressSpaceID,
- IOCommandID ioCommandID,
- IOCommandContents ioCommandContents,
- IOCommandCode ioCommandCode,
- IOCommandKind ioCommandKind);
-
- static OSStatus FWSBP2Initialize (
- RegEntryIDPtr pRegEntryID,
- SInt16 refNum);
-
- static OSStatus FWSBP2Terminate (void);
-
- static OSStatus SBP2Logout ( void );
-
- static OSStatus SBP2DoReadWriteBlocks(
- Boolean isWrite,
- UInt32 count,
- UInt32 sector,
- Ptr buffer,
- Boolean immediate ) ;
-
- static OSStatus FWSBP2Prime(
- AddressSpaceID addressSpaceID,
- IOCommandID ioCommandID,
- IOCommandContents ioCommandContents,
- IOCommandKind ioCommandKind,
- Boolean isWrite);
-
- static OSStatus SBP2Control (
- AddressSpaceID addressSpaceID,
- IOCommandID ioCommandID,
- IOCommandContents ioCommandContents,
- IOCommandKind ioCommandKind);
-
- static OSStatus SBP2Status (
- AddressSpaceID addressSpaceID,
- IOCommandID ioCommandID,
- IOCommandContents ioCommandContents,
- IOCommandKind ioCommandKind);
-
- static OSStatus SBPLoginNotify(
- FWClientSBP2NotifyParamsPtr pFWClientSBP2NotifyParams,
- UInt32 *pCommandAcceptance);
-
- static OSStatus SBPStatusNotify(
- FWClientSBP2NotifyParamsPtr pFWClientSBP2NotifyParams,
- UInt32 *pCommandAcceptance);
-
- static OSStatus SBPUnsolicitedStatusNotify(
- FWClientSBP2NotifyParamsPtr pFWClientSBP2NotifyParams,
- UInt32 *pCommandAcceptance);
-
- static OSStatus SBP2CalculateMediaSize( void );
-
- void ResetFACompletionProc(
- FWCommandObjectID fwCommandObjectID,
- OSStatus commandStatus,
- UInt32 completionProcData);
-
- void BusyTimeoutCompletionProc(
- FWCommandObjectID fwCommandObjectID,
- OSStatus commandStatus,
- UInt32 completionProcData);
-
- void LoginCompletionProc(
- FWCommandObjectID fwCommandObjectID,
- OSStatus commandStatus,
- UInt32 completionProcData);
-
- void ManageCompletionProc(
- FWCommandObjectID fwCommandObjectID,
- OSStatus commandStatus,
- UInt32 completionProcData);
-
- void ReconnectReadCompletionProc(
- FWCommandObjectID fwCommandObjectID,
- OSStatus commandStatus,
- UInt32 completionProcData);
-
- void ReplugCompletionProc(
- FWCommandObjectID fwCommandObjectID,
- OSStatus commandStatus,
- UInt32 completionProcData);
-
- static OSStatus SBP2TUR( Boolean );
-
- static OSStatus SetBUSY_TIMEOUT (void);
-
- static OSStatus FWSBPResetNotify (
- FWClientInterfaceParamsPtr pFWClientInterfaceParams,
- UInt32 *pCommandAcceptance);
-
- static void FWSBPLookForDrive( void );
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // The driver descriptor.
- //
-
- DriverDescription TheDriverDescription =
- {
- kTheDescriptionSignature,
- kInitialDriverDescriptor,
- {
- "\psbp609e,104d8", // Official Mass Storage values
- 1, 0, finalStage, 1,
- },
- {
- kDriverIsUnderExpertControl |
- kDriverIsOpenedUponLoad,
- "\p.FWSBP2DiskDriver",
- },
-
- 1,
- kServiceCategoryNdrvDriver,
- kNdrvTypeIsBlockStorage,
- 1,0,0,0
- };
-
- // Should match above. Probably needs to come from the same constants...
- const NumVersion gFWDiskVersion = {1, 0, finalStage, 0};
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // A quick note on how this works:
- //
- // The SBP2Expert creates sub-nodes for each LUN
- // ...:firewire:fw609e,10483
- // ...:firewire:fw609e,10483:sbpXXXXXX,YYYYYY
- // ...:firewire:fw609e,10483:sbpPPPPPP,QQQQQQ
- //
- // XXXXXX is the command_set_spec_ID of lun 0. YYYYYY is the command_set of lun 0.
- // PPPPPP is the command_set_spec_ID if lun 1. QQQQQQ is the command_set of lun 1. etc.
- //
- // The name of the driver then should match the sub-node created by the expert. To further
- // narrow down the match the SBP2Expert creates a table with the VendorID, SoftwareRev,
- // FirmwareRev, LUN and device_type values from the CSR ROM. This table is contained in
- // a property called "TheDFMTable". The format for this table is in FireWireSBP2.h.
- // A similar table is exported by the driver and is called TheDFMDescriptor. It is exactly
- // twice the size of TheDFMTable as it contains a range for each value exported by the expert.
- // Drivers which match the greatest number of values in the table are selected to match the
- // device. Fields with a negative range are marked as "don't care".
- //
- // Note that "don't care" is different from matching everything. Matching everything means
- // the score for the driver will be incremented for that field while don't care means that
- // it won't be. Thus a driver with 3 matches and 1 don't care scores lower than a driver
- // with 4 matches - even if the matches are the 0 through 0xFFFFFFFF type.
- //
- // Drivers with identical scores will be ranked by version as with other native drivers.
-
-
- // This particular DFMDescriptor isn't very specific. A real driver will need to better
- // identify the device it works with.
-
- SBPMatchData TheDFMDescriptor =
- {
- 0x00000000, 0xFFFFFFFF, // VendorID, don't care
- 0x00000000, 0xFFFFFFFF, // SoftwareRev, don't care
- 0x00000000, 0xFFFFFFFF, // FirmwareRev, don't care
- 0x00000000, 0x00000000, // LUN, match 0x00000000
- 0x00000000, 0x00000000 // device_type, match 0x00000000
- // RBC is always type 0xe.
- };
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Our ICON.
- //
-
- static UInt32 staticIconData[64] =
- {
- 0xFFFFFFFF, 0x80000001, 0x80000001, 0x80000001,
- 0x80000001, 0x80400201, 0x80A00501, 0x81400881,
- 0x82881041, 0x85142021, 0x82281041, 0x80500881,
- 0x80A3C501, 0x80442201, 0x80081001, 0x80081001,
- 0x80081001, 0x80081001, 0x80042001, 0x8003C001,
- 0x80000001, 0x8007E001, 0x80042001, 0x8007E001,
- 0x80000001, 0x8007E001, 0x80042001, 0x8007E001,
- 0x80000001, 0x80000001, 0x80000001, 0xFFFFFFFF,
- 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
- 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
- 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
- 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
- 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
- 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
- 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
- 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF
- };
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Global driver data.
- //
-
- FWSBP2DriverDataPtr gpFWSBP2DriverData = nil;
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // DoDriverIO
- //
- // Main entry point.
- //
-
- OSErr DoDriverIO(
- AddressSpaceID addressSpaceID,
- IOCommandID ioCommandID,
- IOCommandContents ioCommandContents,
- IOCommandCode ioCommandCode,
- IOCommandKind ioCommandKind)
- {
- OSErr err = noErr;
-
- switch (ioCommandCode)
- {
- case kInitializeCommand :
- err = FWSBP2Initialize (&ioCommandContents.initialInfo->deviceEntry, ioCommandContents.initialInfo->refNum);
- break;
-
- case kFinalizeCommand :
- err = FWSBP2Terminate ();
- break;
-
- case kOpenCommand :
- break;
-
- case kReadCommand :
- err = FWSBP2Prime (addressSpaceID,
- ioCommandID,
- ioCommandContents,
- ioCommandKind,
- false);
- break;
-
- case kWriteCommand :
- err = FWSBP2Prime (addressSpaceID,
- ioCommandID,
- ioCommandContents,
- ioCommandKind,
- true);
- break;
- case kCloseCommand :
- err = SBP2Logout();
- break;
-
- case kControlCommand :
- err = SBP2Control(addressSpaceID,
- ioCommandID,
- ioCommandContents,
- ioCommandKind);
- break;
-
- case kStatusCommand :
- err = SBP2Status(addressSpaceID,
- ioCommandID,
- ioCommandContents,
- ioCommandKind);
- break;
-
- default :
- err = paramErr;
- }
-
- return (err);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // FWSBP2Initialize
- //
- // This routine initializes the FireWire SBP2 sample driver. It
- // allocates a private data record and registers with the FireWire family.
- // It also prepares some command objects for use later on.
- //
-
- static OSStatus SBPLoginNotify(
- FWClientSBP2NotifyParamsPtr pFWClientSBP2NotifyParams,
- UInt32 *pCommandAcceptance);
-
- static OSStatus FWSBP2Initialize(
- RegEntryIDPtr pRegEntryID,
- SInt16 refNum)
- {
- FWSBP2DriverDataPtr pFWSBP2DriverData = nil;
- FWDriverID fwDriverID;
- QHdrPtr pDrvQHdr;
- DrvQElPtr pDrvQEl;
- short driveNum;
- UInt32 orbNum;
- UInt32 keepTrying;
- UInt32 sizeTemp;
- FWAddress addrTemp;
- UInt32 deviceFlags;
- OSStatus status = noErr;
-
- // Allocate our driver data.
- pFWSBP2DriverData =
- (FWSBP2DriverDataPtr) PoolAllocateResident (sizeof (FWSBP2DriverData), true);
- if (pFWSBP2DriverData == nil)
- {
- status = memFullErr;
- }
- else
- gpFWSBP2DriverData = pFWSBP2DriverData;
-
- // Register with the FireWire family.
- if (status == noErr)
- {
- status = FWRegisterDriver (pRegEntryID,
- &fwDriverID,
- &(pFWSBP2DriverData->csrUnitID),
- (UInt32) pFWSBP2DriverData);
-
- if (status == noErr)
- pFWSBP2DriverData->fwDriverID = fwDriverID;
-
- }
-
- // Set the maximum packet payload size.
- if (status == noErr)
- {
- status = FWSetMaxPayloadSize ((FWReferenceID) pFWSBP2DriverData->fwDriverID, kDiskDriverPayloadSize);
- }
-
- // Tell FSL we want it to violate 1394-1995 by retrying when we underflow sending a response
- // and get ack_data_err.
- // Only do this if you know your device won't be confused if the Mac retries a response.
- if (status == noErr)
- {
- // Note that we're running at task level, so if anyone tried to set flags
- // between these two calls at non-task level we might undo their change.
-
- status = FWGetFWDeviceFlags ((FWReferenceID) pFWSBP2DriverData->fwDriverID, &deviceFlags);
-
- deviceFlags |= kFWDeviceRetryOnAckDataErr;
-
- if (status == noErr)
- status = FWSetFWDeviceFlags ((FWReferenceID) pFWSBP2DriverData->fwDriverID, deviceFlags);
- }
-
- // Allocate login command object.
- if (status == noErr)
- {
- status = FWAllocateSBP2LoginCommandObject ((FWReferenceID) pFWSBP2DriverData->fwDriverID,
- &pFWSBP2DriverData->loginCommandID);
- }
-
- if (status != noErr) pFWSBP2DriverData->loginCommandID = 0;
-
- // Prepare login command object.
- if (status == noErr)
- {
- status = FWSetSBP2LoginCommandFlags (pFWSBP2DriverData->loginCommandID,
- kSBP2NotifyOnLoginComplete |
- kSBP2NotifyOnLoginFailed |
- kSBP2NotifyOnReconnecting |
- kSBP2NotifyOnReconnectComplete |
- kSBP2NotifyOnReconnectFailed |
- kSBP2ExclusiveLogin );
- }
-
- if (status == noErr)
- {
- status = FWSetSBP2LoginCommandLoginNotifyProc (pFWSBP2DriverData->loginCommandID,
- SBPLoginNotify,
- (UInt32) pFWSBP2DriverData);
- }
-
- if (status == noErr)
- {
- status = FWSetSBP2LoginCommandStatusNotifyProc (pFWSBP2DriverData->loginCommandID,
- SBPStatusNotify,
- (UInt32) pFWSBP2DriverData);
- }
-
- if (status == noErr)
- {
- status = FWSetSBP2LoginCommandUnsolicitedStatusNotifyProc (pFWSBP2DriverData->loginCommandID,
- SBPUnsolicitedStatusNotify,
- (UInt32) pFWSBP2DriverData);
- }
-
- if (status == noErr)
- {
- status = FWSetFWCommandCompletionProc (pFWSBP2DriverData->loginCommandID,
- LoginCompletionProc);
- }
-
- if (status == noErr)
- {
- status = FWSetSBP2LoginCommandMaxPayloadSize (pFWSBP2DriverData->loginCommandID, kDiskDriverPayloadSize );
- }
-
- if( status == noErr)
- {
- status = FWAllocateSBP2ManagementCommandObject((FWReferenceID) pFWSBP2DriverData->fwDriverID,
- &pFWSBP2DriverData->fwLUNReset_ID);
- }
-
- if( status == noErr )
- {
- status = FWSetSBP2ManagementCommandFunction(pFWSBP2DriverData->fwLUNReset_ID, kSBP2LogicalUnitReset);
- }
-
- if( status == noErr )
- {
- status = FWSetSBP2ManagementCommandCommandID( pFWSBP2DriverData->fwLUNReset_ID,
- pFWSBP2DriverData->loginCommandID);
- }
-
- if (status == noErr)
- {
- status = FWSetFWCommandCompletionProc (pFWSBP2DriverData->fwLUNReset_ID,
- ManageCompletionProc);
- }
-
- for( orbNum = 0; orbNum < kTotalORBs; orbNum++ ) {
- // Allocate an ORB command object.
- if (status == noErr)
- {
- status = FWAllocateSBP2NormalCommandObject (pFWSBP2DriverData->loginCommandID,
- &pFWSBP2DriverData->orbID[orbNum]);
-
- // Memory is not automatically set aside for ORBs. If we ever want to set up an
- // ORB at non-task level, we will need to have memory allocated in advance.
-
- if (status == noErr)
- status = FWAllocateFWCommandObjectMemory (pFWSBP2DriverData->orbID[orbNum], 12288);
-
- if (status == noErr)
- status = FWSetSBP2NormalCommandTimeout (pFWSBP2DriverData->orbID[orbNum], durationMillisecond * 1000);
- }
-
- if (status != noErr) {
- pFWSBP2DriverData->orbID[orbNum] = 0;
- break;
- }
-
- }
-
- pFWSBP2DriverData->currentORB = kAsyncORB; // Switch between kAsyncORB and kAsyncORB + 1
- // Makes debugging easier since we can see
- // each new request go by in FireBug and also
- // in the receive buffer of the FWIM
- // Not really needed though.
-
- // Allocate an async command object for writing to the AGENT_RESET register.
- // Need this in case the drive goes out to lunch. Writing this register doesn't always
- // work, sometimes a bus reset or even power cycle is required. I don't know why yet
- if (status == noErr)
- {
- status = FWAllocateAsynchCommandObject (&pFWSBP2DriverData->fwAGENT_RESET_ID);
- }
-
- if (status == noErr)
- {
- status = FWSetFWCommandParams (pFWSBP2DriverData->fwAGENT_RESET_ID,
- pFWSBP2DriverData->fwDriverID,
- 0,
- ResetFACompletionProc,
- 0);
- }
-
- // Allocate an async command object for reading from the drive after it has gone
- // away long enough for a reconnect to fail. We issue this read after any bus reset
- // following a reconnect failed to see if our device came back.
- if (status == noErr)
- {
- status = FWAllocateAsynchCommandObject (&pFWSBP2DriverData->fwReconnectID);
- }
-
- if (status == noErr)
- {
- status = FWSetFWCommandParams (pFWSBP2DriverData->fwReconnectID,
- pFWSBP2DriverData->fwDriverID,
- 0,
- ReconnectReadCompletionProc,
- 0);
- }
-
- // Allocate an async command object for requesting a replug if the drive
- // went away on us while we have volumes mounted.
-
- if (status == noErr)
- {
- status = FWAllocateFWCommandObject (&pFWSBP2DriverData->fwReplugID);
- }
-
- if (status == noErr)
- {
- status = FWSetFWCommandParams (pFWSBP2DriverData->fwReplugID,
- pFWSBP2DriverData->fwDriverID,
- 0,
- ReplugCompletionProc,
- 0);
- }
-
- // Allocate an asynch command object to set the BUSY_TIMEOUT register after each login.
- // This is kind of gross, but to do it right would be complicated and need some kind of
- // state machine.
-
- if (status == noErr)
- {
- status = FWAllocateAsynchCommandObject (&pFWSBP2DriverData->busyTimeoutCommandID);
- }
-
- if (status == noErr)
- {
- status = FWSetFWCommandParams (pFWSBP2DriverData->busyTimeoutCommandID,
- pFWSBP2DriverData->fwDriverID, // Device to write to
- 0, // Flags (asynch)
- BusyTimeoutCompletionProc, // Completion proc
- 0); // Completion proc data
- }
-
- if (status == noErr)
- {
- status = FWSetAsynchCommandParams (pFWSBP2DriverData->busyTimeoutCommandID,
- 0, // Generation (unused)
- 0xffff, // Address (high 16 bits)
- 0xf0000210, // Address (low 32 bits)
- (Ptr) &pFWSBP2DriverData->busyTimeout, // Payload (set later)
- 4, // Payload size
- 4, // Max payload
- 50, // Retries
- 0); // Flags (none)
- }
-
- // Prepare a small well-aligned buffer for small requests
- if (status == noErr)
- {
- status = FWAllocateSBP2NormalCommandObject (pFWSBP2DriverData->loginCommandID,
- &pFWSBP2DriverData->smallBufferORB);
- if (status == noErr)
- status = FWAllocateFWCommandObjectMemory (pFWSBP2DriverData->smallBufferORB, 12288);
-
- if (status == noErr)
- {
- // The documentation doesn't guarantee it, but this function always
- // returns page-aligned memory.
-
- pFWSBP2DriverData->smallBuffer =
- MemAllocatePhysicallyContiguous (kSmallDoubleBufferSize, false);
-
- if (!pFWSBP2DriverData->smallBuffer)
- status = memFullErr;
- }
-
- // FWSetSBP2NormalCommandBuffers copies all it's arguments and is synchronous
- // so we can pass pointers from the stack for our buffer/length list. By assigning
- // the full buffer here, SBP-2 will be able to optimize when we use only part of
- // the buffer, by avoiding the PrepareMemoryForIO.
-
- sizeTemp = kSmallDoubleBufferSize;
- addrTemp.addressHi = 0;
- addrTemp.addressLo = (UInt32) pFWSBP2DriverData->smallBuffer;
-
- if (status == noErr)
- status = FWSetSBP2NormalCommandBuffers (pFWSBP2DriverData->smallBufferORB, 1, &addrTemp, &sizeTemp);
-
- if (status == noErr)
- status = FWSetSBP2NormalCommandTimeout (pFWSBP2DriverData->smallBufferORB, durationMillisecond * 1000);
- }
-
- // We are going to try to log in. Make sure nobody ejects our interface.
- if (status == noErr)
- {
- status = FWGetFWDeviceFlags ((FWReferenceID) gpFWSBP2DriverData->fwDriverID, &deviceFlags);
-
- deviceFlags |= kFWDeviceDoNotEjectCardBus;
-
- if (status == noErr)
- status = FWSetFWDeviceFlags ((FWReferenceID) gpFWSBP2DriverData->fwDriverID, deviceFlags);
- }
-
- // Save our driver data or clean up on error.
- if (status == noErr)
- {
-
- gpFWSBP2DriverData->drvrRefNum = refNum;
- // And go ahead and login to the drive.
- // !!!zzz realistically we need to make sure this drive
- // belongs to us but for now we'll assume it does
- gpFWSBP2DriverData->pRegEntryID = *pRegEntryID;
-
- // BusManagementNotify didn't work...
- FWSetFWClientResetNotifyProc(gpFWSBP2DriverData->fwDriverID, FWSBPResetNotify );
-
- pFWSBP2DriverData->loggedIn = false;
- pFWSBP2DriverData->loginObjBusy = true;
-
- status = FWSBP2Login (gpFWSBP2DriverData->loginCommandID);
-
- while( gpFWSBP2DriverData->loginObjBusy )
- ;
-
- if( !pFWSBP2DriverData->loggedIn ) {
-
- // We failed to log in. We don't care if someone ejects our interface now.
-
- status = FWGetFWDeviceFlags ((FWReferenceID) gpFWSBP2DriverData->fwDriverID, &deviceFlags);
-
- deviceFlags &= ~kFWDeviceDoNotEjectCardBus;
-
- if (status == noErr)
- status = FWSetFWDeviceFlags ((FWReferenceID) gpFWSBP2DriverData->fwDriverID, deviceFlags);
-
- return( openErr );
- }
- }
- else
- {//zzz should use terminate
- if (pFWSBP2DriverData != nil)
- PoolDeallocate ((Ptr) pFWSBP2DriverData);
- }
-
- // If we got logged in, set the BUSY_TIMEOUT register so that the drive
- // will retry if we busy a packet it sends us.
- if (status == noErr)
- status = SetBUSY_TIMEOUT ();
-
- // Try a few of these - helps you wake up in the morning. Sort of like a double latte.
-
- keepTrying = 25;
- while( keepTrying-- && SBP2TUR(true) )
- ;
-
- if( status == noErr )
- status = SBP2CalculateMediaSize();
-
- HLock((Handle)GetDCtlEntry (refNum));
- gpFWSBP2DriverData->dce = *(GetDCtlEntry (refNum));
-
- // Set up stuff before drive queue element.
- if (status == noErr)
- {
- gpFWSBP2DriverData->driveStatus.diskInPlace = 1;
- gpFWSBP2DriverData->driveStatus.installed = 1;
- gpFWSBP2DriverData->driveStatus.qType = 1;
- }
-
- // Compute drive size.
- if (status == noErr)
- {
- gpFWSBP2DriverData->driveStatus.driveSize = gpFWSBP2DriverData->totalBlocks & 0xFFFF;
- gpFWSBP2DriverData->driveStatus.driveS1 = (short)(gpFWSBP2DriverData->totalBlocks >> 16);
- }
-
- // Find a drive number to use, starting with number 8.
- if (status == noErr)
- {
- driveNum = 8;
- pDrvQHdr = GetDrvQHdr ();
- pDrvQEl = (DrvQElPtr) (pDrvQHdr->qHead);
- while (pDrvQEl)
- {
- if ((pDrvQEl->dQDrive == driveNum) ||
- ((pDrvQEl->dQDrive + 1) == driveNum))//zzz hack to work around AddDrive bug.
- {
- driveNum++;
- pDrvQEl = (DrvQElPtr) (pDrvQHdr->qHead);
- }
- else
- {
- pDrvQEl = (DrvQElPtr) pDrvQEl->qLink;
- }
- }
-
- gpFWSBP2DriverData->driveStatus.dQDrive = driveNum;
- }
-
- // Add the drive to the drive queue.
- if (status == noErr)
- {
- gpFWSBP2DriverData->queuedDQEl = true;
- AddDrive (refNum,
- gpFWSBP2DriverData->driveStatus.dQDrive,
- (DrvQEl *) &(gpFWSBP2DriverData->driveStatus.qLink));
- }
-
- // Notify interested parties that a new drive has been added.
- //zzz should we check error?
- if (status == noErr)
- {
- PostEvent (diskEvt, (UInt32) gpFWSBP2DriverData->driveStatus.dQDrive);
- }
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // FWSBP2Terminate
- //
- // This routine terminates the FireWire SBP2 sample driver. It
- // deallocates a private data record and unregisters with the FireWire family.
- //
- // Note, currently this routine is never called.
- // Even if you unplug the device, nobody terminates the driver.
- //
-
- static OSStatus FWSBP2Terminate(void)
- {
- OSStatus status = noErr;
- UInt32 orbNum;
-
- if (gpFWSBP2DriverData != nil)
- {
-
- if (gpFWSBP2DriverData->loginCommandID)
- FWDeallocateFWCommandObject (gpFWSBP2DriverData->fwAGENT_RESET_ID);
-
- if (gpFWSBP2DriverData->loginCommandID)
- FWDeallocateFWCommandObject (gpFWSBP2DriverData->fwReconnectID);
-
- if( gpFWSBP2DriverData->queuedDQEl )
- Dequeue( (QElemPtr)&gpFWSBP2DriverData->driveStatus.qLink, LMGetDrvQHdr() );
-
- //zzz We should check that ORB is not active before we deallocate it.
- // We could issue a target reset to guarantee this.
-
- for( orbNum = 0; orbNum < kTotalORBs; orbNum++ ) {
- if (gpFWSBP2DriverData->orbID[orbNum])
- FWDeallocateFWCommandObject (gpFWSBP2DriverData->orbID[orbNum]);
- }
-
- if( gpFWSBP2DriverData->loggedIn )
- SBP2Logout();
-
- if (gpFWSBP2DriverData->smallBuffer)
- MemDeallocatePhysicallyContiguous (gpFWSBP2DriverData->smallBuffer);
-
- if (gpFWSBP2DriverData->smallBufferORB)
- FWDeallocateFWCommandObject (gpFWSBP2DriverData->smallBufferORB);
-
- if (gpFWSBP2DriverData->loginCommandID)
- FWDeallocateFWCommandObject (gpFWSBP2DriverData->loginCommandID);
-
- // Unregister with FireWire family.
- if (gpFWSBP2DriverData->fwDriverID != kInvalidFWDriverID)
- FWUnregisterDriver (gpFWSBP2DriverData->fwDriverID);
-
- // Deallocate our driver data.
- PoolDeallocate ((Ptr) gpFWSBP2DriverData);
- gpFWSBP2DriverData = nil;
- }
-
- return status;
- }
-
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // SBP2Logout
- //
- // This routine performs a logout.
- //
-
- static OSStatus SBP2Logout( void )
- {
- UInt32 deviceFlags;
- OSStatus status = noErr;
-
- gpFWSBP2DriverData->loginObjBusy = true;
-
- status = FWSBP2Logout (gpFWSBP2DriverData->loginCommandID);
-
- while( gpFWSBP2DriverData->loginObjBusy )
- ;
-
- if (status == noErr)
- {
- gpFWSBP2DriverData->loggedIn = false;
-
- // We no longer care if anyone ejects our interface.
- status = FWGetFWDeviceFlags ((FWReferenceID) gpFWSBP2DriverData->fwDriverID, &deviceFlags);
-
- deviceFlags &= ~kFWDeviceDoNotEjectCardBus;
-
- if (status == noErr)
- status = FWSetFWDeviceFlags ((FWReferenceID) gpFWSBP2DriverData->fwDriverID, deviceFlags);
- }
-
- return noErr;
- }
-
-
- static OSStatus FWSBP2Prime(
- AddressSpaceID addressSpaceID,
- IOCommandID ioCommandID,
- IOCommandContents ioCommandContents,
- IOCommandKind ioCommandKind,
- Boolean isWrite)
- {
- OSStatus status;
- UInt32 startblk;
- UInt32 numblks;
- IOParamPtr ioPB;
-
- // save away some info about the current command (assume single threaded for now).
- gpFWSBP2DriverData->ioPB = ioPB = (IOParamPtr) ioCommandContents.pb;
- gpFWSBP2DriverData->ioCommandID = ioCommandID;
- gpFWSBP2DriverData->isWrite = isWrite;
-
- // calculate the starting block and block count (divide by 512)
-
- if( ioPB->ioPosMode & 0x0100) { // large volume format (>=4GB)
- startblk = ( *(UInt32 *)((char*)&(ioPB->ioPosOffset)+2) << (16-9) ) +
- ( *(UInt16 *)((char*)&(ioPB->ioPosOffset)+6) >> 9 );
- }
- else // regular volume format (<4GB)
- startblk = (UInt32)(ioPB->ioPosOffset) >> 9;
-
- numblks = (UInt32)(ioPB->ioReqCount) >> 9;
-
- // Is count an integer number of blocks or block out of range of partition ?
- if( ((ioPB->ioReqCount & (kBlockSize-1)) != 0) ||
- (startblk+numblks > gpFWSBP2DriverData->totalBlocks))
- {
- status = paramErr;
- }
- else
- {
- gpFWSBP2DriverData->retriesLeft = 30; // Totally arbitrary, probably overkill
-
- gpFWSBP2DriverData->ioPending = true;
-
- // Decide if we should use the small, fixed double buffer
- if (ioPB->ioReqCount <= kSmallDoubleBufferSize)
- {
- gpFWSBP2DriverData->useSmallBuffer = true;
- gpFWSBP2DriverData->immediate = (ioCommandKind == kImmediateIOCommandKind);
- if (isWrite) BlockMoveData (ioPB->ioBuffer, gpFWSBP2DriverData->smallBuffer, ioPB->ioReqCount);
-
- // if this is a read we'll copy data out when we get good status
- }
- else
- {
- gpFWSBP2DriverData->useSmallBuffer = false;
- }
-
- // Can't hardly do nuthin if we aint logged in
- if( !gpFWSBP2DriverData->loggedIn ) {
-
- // For immediate command just bail with IOErr
- if( ioCommandKind == kImmediateIOCommandKind ) {
- return( ioErr );
- }
- else if( gpFWSBP2DriverData->returnDiskErr ) {
- // If user canceled our dialog return disk error to get clear any sync-wait
- // loops and allow the machine to keep operating. For all we know the reason the
- // drive went away was because the user spilled coffee on it and now they want
- // to save their open files somewhere else.
- IOCommandIsComplete (gpFWSBP2DriverData->ioCommandID, ioErr);
- return( ioErr );
- }
- else {
- // Dialog should still be on the screen, go away and wait for notification
- // and retry the command then.
- gpFWSBP2DriverData->count = numblks;
- gpFWSBP2DriverData->sector = startblk;
- gpFWSBP2DriverData->buffer = ioPB->ioBuffer;
- return( ioInProgress );
- }
- }
-
- // Make call synchronously if we are an immediate call, else normal
- status = SBP2DoReadWriteBlocks( isWrite, numblks, startblk, ioPB->ioBuffer, ioCommandKind == kImmediateIOCommandKind );
-
- }
- if( status != ioInProgress ) {
- ioPB->ioActCount = 0; /* report all or none */
- IOCommandIsComplete (gpFWSBP2DriverData->ioCommandID, status);
- }
- return(status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // SBP2DoReadWriteBlocks
- //
- // This routine reads block zero, assuming the target is a simple hard drive.
- //
- // The sync flag implies immediate. Don't ever call it with this flag true at
- // interrupt time. This will be used for device manager immediate calls and
- // probably partition map scanning code. Everything else should be asynchronous.
- //
-
- static OSStatus SBP2DoReadWriteBlocks(
- Boolean isWrite,
- UInt32 count,
- UInt32 sector,
- Ptr buffer,
- Boolean immediate )
- {
- FWCommandObjectID orbID;
- OSStatus status = noErr;
- #if VerifyWrites
- Boolean wasVerify;
- #endif
- UInt8 *command;
-
- // Remember some stuff for retries
- gpFWSBP2DriverData->count = count;
- gpFWSBP2DriverData->sector = sector;
- gpFWSBP2DriverData->buffer = buffer;
-
- // Double buffer if not aligned to drive's liking and not already using the small buffer
- if( ((long)buffer & 0x0000000F) && !gpFWSBP2DriverData->useSmallBuffer )
- gpFWSBP2DriverData->doubleBuffer = true;
- else
- gpFWSBP2DriverData->doubleBuffer = false;
-
- #if VerifyWrites
- wasVerify = gpFWSBP2DriverData->needsVerify;
- if( isWrite )
- gpFWSBP2DriverData->needsVerify = true;
- #endif
-
- gpFWSBP2DriverData->xferLeft = 0; // assume no extra transfer
-
- if( count > kMaxTransfer ) { // Transfer too big to do all at once?
- gpFWSBP2DriverData->xferLeft = count-kMaxTransfer;
- count = kMaxTransfer;
- gpFWSBP2DriverData->next_block = sector + count;
-
- #if VerifyWrites
- if( !wasVerify ) {
- #endif
- gpFWSBP2DriverData->next_buffer = buffer + (count << 9);
- #if VerifyWrites
- }
- #endif
- }
-
- if (gpFWSBP2DriverData->useSmallBuffer)
- {
- orbID = gpFWSBP2DriverData->smallBufferORB;
- }
- else
- {
- if( isWrite && gpFWSBP2DriverData->doubleBuffer )
- BlockMoveData (buffer, gpFWSBP2DriverData->dataBuffer, count << 9);
-
- if( immediate )
- orbID = gpFWSBP2DriverData->orbID[kImmedORB];
- else {
- orbID = gpFWSBP2DriverData->orbID[gpFWSBP2DriverData->currentORB];
-
- // Switch to the other ORB for next transaction
- gpFWSBP2DriverData->currentORB = ( gpFWSBP2DriverData->currentORB ? 0 : 1);
- }
- }
-
- // Prepare the ORB.
- // Page table total length must agree with ATAPI request length, or drive
- // will get confused.
-
- gpFWSBP2DriverData->buffers[0].addressHi = 0;
- gpFWSBP2DriverData->lengths[0] = (count << 9);
-
- if (gpFWSBP2DriverData->useSmallBuffer)
- {
- gpFWSBP2DriverData->buffers[0].addressLo = (UInt32) gpFWSBP2DriverData->smallBuffer;
-
- // This one won't call PrepareMemoryForIO because it's the same buffer we gave it before.
- status = FWSetSBP2NormalCommandBuffers (orbID, 1, gpFWSBP2DriverData->buffers, gpFWSBP2DriverData->lengths);
- }
- else
- {
- if( gpFWSBP2DriverData->doubleBuffer )
- gpFWSBP2DriverData->buffers[0].addressLo = (UInt32) gpFWSBP2DriverData->dataBuffer;
- else
- gpFWSBP2DriverData->buffers[0].addressLo = (UInt32) buffer;
-
- status = FWSetSBP2NormalCommandBuffers (orbID, 1, gpFWSBP2DriverData->buffers, gpFWSBP2DriverData->lengths);
- }
-
- // Form ATAPI command (SCSI-3, cribbed from MMC-2 spec)
- command = &gpFWSBP2DriverData->command[0];
-
- command[0] = (isWrite ? 0x2A : 0x28); // Write or Read
- command[1] = 0; // Mostly reserved
- command[2] = (sector >> 24) & 0xff; // MSB of LBA
- command[3] = (sector >> 16) & 0xff;
- command[4] = (sector >> 8) & 0xff;
- command[5] = sector & 0xff; // LSB of LBA
- command[6] = 0; // Reserved
- command[7] = (count >> 8) & 0xff; // MSB of block count
- command[8] = count & 0xff; // LSB of block count
- command[9] = 0; // Control (reserved)
- command[10] = 0;
- command[11] = 0x02; // Used DMA
-
- if (status == noErr)
- status = FWSetSBP2NormalCommandCommand (orbID, (Ptr) command, 12);
-
- if (status == noErr)
- status = FWSetSBP2NormalCommandFlags (orbID,
- (isWrite ? 0 : kSBP2CommandTransferDataFromTarget) |
- kSBP2CommandCompleteNotify |
- kSBP2CommandImmediate |
- kSBP2CommandNormalORB);
-
- if( immediate ) {
- if (status == noErr)
- status = FWSetFWCommandFlags (orbID, kFWCommandSyncFlag);
- }
- else {
- if (status == noErr)
- status = FWSetFWCommandFlags (orbID, 0);
- }
-
- if (status == noErr)
- status = FWAppendSBP2Command (orbID);
-
- if( (status == noErr) && immediate )
- {
- // Wait for completion
- // Remember kiddies - don't do this at interrupt time!
- while( gpFWSBP2DriverData->immedStatus == ioInProgress )
- ;
- status = gpFWSBP2DriverData->immedStatus;
-
- // For immediate reads, now copy data out of our private buffer
- if (!isWrite)
- {
- if (gpFWSBP2DriverData->useSmallBuffer)
- {
- BlockMoveData (gpFWSBP2DriverData->smallBuffer, buffer, count << 9);
- }
- else
- {
- if (gpFWSBP2DriverData->doubleBuffer)
- BlockMoveData (gpFWSBP2DriverData->dataBuffer, buffer, count << 9);
- }
- }
- }
-
- if( (status == noErr) && !immediate ) {
- return( ioInProgress );
- }
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // SBPLoginNotify
- //
- // This routine is called when a login command completes.
- //
-
- static OSStatus SBPLoginNotify(
- FWClientSBP2NotifyParamsPtr pFWClientSBP2NotifyParams,
- UInt32 *pCommandAcceptance)
- {
-
- if (pFWClientSBP2NotifyParams->notificationEvent == kSBP2LoginComplete)
- {
- gpFWSBP2DriverData->loggedIn = true;
- gpFWSBP2DriverData->returnDiskErr = false;
-
- // Set the BUSY_TIMEOUT register again.
- if (gpFWSBP2DriverData->busyTimeoutCommandBusy)
- {
- gpFWSBP2DriverData->busyTimeoutAgain = true;
- // Will set it again when the command finishes.
- }
- else
- {
- // Do this only if it's already been set (ie not first time)
- if (gpFWSBP2DriverData->busyTimeout)
- if (FWWrite (gpFWSBP2DriverData->busyTimeoutCommandID) == noErr)
- gpFWSBP2DriverData->busyTimeoutCommandBusy = true;
- }
-
- // If the user ejected the disk and then put it back we need to post a diskEvent to tell the File System
- if( gpFWSBP2DriverData->gotEject )
- PostEvent (diskEvt, (UInt32) gpFWSBP2DriverData->driveStatus.dQDrive);
-
- // Async login for reconnect?
- if( gpFWSBP2DriverData->wasLoggedIn ) {
-
- if( gpFWSBP2DriverData->ioPending && gpFWSBP2DriverData->retriesLeft-- ) {
- SBP2DoReadWriteBlocks( gpFWSBP2DriverData->isWrite, gpFWSBP2DriverData->count, gpFWSBP2DriverData->sector, gpFWSBP2DriverData->buffer, false);
- }
- }
-
- gpFWSBP2DriverData->wasLoggedIn = true;
- gpFWSBP2DriverData->gotEject = false; // volumes should be back.
-
- gpFWSBP2DriverData->fetchAgent.addressHi =
- *(((UInt32 *) (pFWClientSBP2NotifyParams->loginResponse)) + 1);
- gpFWSBP2DriverData->fetchAgent.addressLo =
- *(((UInt32 *) (pFWClientSBP2NotifyParams->loginResponse)) + 2);
-
- }
-
- if (pFWClientSBP2NotifyParams->notificationEvent == kSBP2Reconnecting)
- {
- // Sit on any incoming requests until we are reconnected. They'll fail anyway.
- gpFWSBP2DriverData->loggedIn = false;
- gpFWSBP2DriverData->reconnecting = true;
-
- }
- else
- gpFWSBP2DriverData->reconnecting = false;
-
-
- if (pFWClientSBP2NotifyParams->notificationEvent == kSBP2ReconnectComplete)
- {
- gpFWSBP2DriverData->loggedIn = true;
-
- // Set the BUSY_TIMEOUT register again.
- if (gpFWSBP2DriverData->busyTimeoutCommandBusy)
- {
- gpFWSBP2DriverData->busyTimeoutAgain = true;
- // Will set it again when the command finishes.
- }
- else
- {
- // Do this only if it's already been set (ie not first time)
- if (gpFWSBP2DriverData->busyTimeout)
- if (FWWrite (gpFWSBP2DriverData->busyTimeoutCommandID) == noErr)
- gpFWSBP2DriverData->busyTimeoutCommandBusy = true;
- }
-
- // Restart pending IO if it exists.
- if( gpFWSBP2DriverData->ioPending ) {
- if( gpFWSBP2DriverData->retriesLeft-- ) {
- SBP2DoReadWriteBlocks( gpFWSBP2DriverData->isWrite, gpFWSBP2DriverData->count, gpFWSBP2DriverData->sector, gpFWSBP2DriverData->buffer, false);
- }
- else {
- gpFWSBP2DriverData->ioPending = false;
- IOCommandIsComplete (gpFWSBP2DriverData->ioCommandID, ioErr);
- }
- }
- }
-
- if (pFWClientSBP2NotifyParams->notificationEvent == kSBP2LoginFailed) {
-
- // is this is the first login?
- if( gpFWSBP2DriverData->wasLoggedIn ) {
- // Hmmm. Did somebody else log into our drive while it was off the bus
- // or did something else prevent us from logging in? Perhaps the Mac Timed
- // out before the drive did and the drive rejected our login request because
- // it thought it had a valid login? For a single initiator environment the
- // a good thing to do is probably try to login again until we succeed. Perhaps
- // even better would be to do this for the reconnect timeout + 1 second and
- // then start returning ioErr to the clients. I'll leave that as an exercise
- // for the developers. This driver will just blindly keep trying to login.
- //
- // I changed this because after receiving wall-powered drives we noticed it
- // was possible to get a bizzare flashing dialog effect on a re-plug because
- // the Mac and the Drive were out of sync with regard to a valid login
-
- gpFWSBP2DriverData->loggedIn = false;
- gpFWSBP2DriverData->wait4Replug = false;
- FWSBPLookForDrive();
- }
- else
- gpFWSBP2DriverData->loggedIn = false;
- }
-
- if (pFWClientSBP2NotifyParams->notificationEvent == kSBP2ReconnectFailed) {
-
- // if we didn't expect the drive to go away demand that the user put it back
- // Important - this function is always asynchronous to allow FSL to make forward
- // progress. We'll find out what happend (came back or user cancelled with Command-.)
- // in the completion routine.
-
- gpFWSBP2DriverData->loggedIn = false;
-
- if( !gpFWSBP2DriverData->gotEject ) {
- gpFWSBP2DriverData->wait4Replug = true;
- FWWaitForDeviceRePlug( gpFWSBP2DriverData->fwReplugID );
- }
-
- }
-
- *pCommandAcceptance = kFWClientCommandAcceptNoMore;
- return FWClientCommandIsComplete (pFWClientSBP2NotifyParams->fwClientInterfaceParams.fwClientCommandID, 0);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // SBPStatusNotify
- //
- // This routine is called when an ORB generates status.
- // This routine is a complete mess. I hate SBP2 error reporting. How may ways are
- // there to tell you something went wrong?
- //
-
- static OSStatus SBPStatusNotify(
- FWClientSBP2NotifyParamsPtr pFWClientSBP2NotifyParams,
- UInt32 *pCommandAcceptance)
- {
- OSStatus compStatus;
- OSStatus status;
- OSStatus cmdStatus = ioErr;
- sbpStatusBlockPtr sbpStatus;
- FWCommandObjectID completedOrb; // Which guy just finished
- Boolean statusValid = false;
- UInt32 bufferLength;
- #if VerifyWrites
- UInt32 x;
- char debugStr[256];
- #endif
- Boolean commandSuccessful = false;
-
- *pCommandAcceptance = kFWClientCommandAcceptNoMore;
- compStatus = FWClientCommandIsComplete (pFWClientSBP2NotifyParams->fwClientInterfaceParams.fwClientCommandID, 0);
-
- if( ! (gpFWSBP2DriverData->loginObjBusy || gpFWSBP2DriverData->reconnecting) ) // Bogus timeout status?
- { //Don't bother trying anything until we're connected to the device
- switch (pFWClientSBP2NotifyParams->notificationEvent)
- {
-
- case kSBP2NormalCommandStatus:
- if ((pFWClientSBP2NotifyParams->message) && (pFWClientSBP2NotifyParams->length)) {
- statusValid = true;
- sbpStatus = (sbpStatusBlockPtr)pFWClientSBP2NotifyParams->message;
-
- // Always reset the FA if it reports dead status
- if (sbpStatus->stSrcRespLen & 0x08) {
-
- status = FWSetAsynchCommandParams
- (gpFWSBP2DriverData->fwAGENT_RESET_ID,
- 0, // generation - ignored
- gpFWSBP2DriverData->fetchAgent.addressHi, // addr from login response
- gpFWSBP2DriverData->fetchAgent.addressLo + 4, // + 4 to get AGENT_RESET
- (Ptr) gpFWSBP2DriverData, // any valid pointer will do
- 4, // quadlet write
- 0, // max payload - ignored
- 8, // max retries
- 0); // no flags
-
- // Reset agent
- if (status == noErr)
- {
- FWWrite (gpFWSBP2DriverData->fwAGENT_RESET_ID);
- return( noErr ); // Pick up thread from completionProc and retry command
- }
- }
- else if( (sbpStatus->stSrcRespLen & 0x30) == 0 && sbpStatus->stSBPStatus == 0 ) {
-
- if( (sbpStatus->stSrcRespLen & 0x07) == 1 ) {
-
- cmdStatus = noErr;
- }
- }
- }
-
- // If no IO is in progress this was the Request Sense we did during initialization
- // or some other IO not connected with an IO. Don't start retry state machine.
- if( !gpFWSBP2DriverData->ioPending )
- break;
-
- // If this was a prime command then either call ioDone or start
- // the next chunk of the transfer
- if( statusValid && (gpFWSBP2DriverData->command[0] == 0x2a || gpFWSBP2DriverData->command[0] == 0x28) ) {
-
- if( cmdStatus == noErr ) {
-
- if( gpFWSBP2DriverData->count > kMaxTransfer )
- bufferLength = kMaxTransfer << 9;
- else
- bufferLength = gpFWSBP2DriverData->count << 9;
-
- // If read, small-buffer, and not sync, copy data out
- // (immediate calls will copy out elsewhere - zzz I think it's redundant, clean it up)
- if ((!gpFWSBP2DriverData->isWrite) &&
- (gpFWSBP2DriverData->useSmallBuffer) &&
- (!gpFWSBP2DriverData->immediate))
- {
- BlockMoveData (gpFWSBP2DriverData->smallBuffer, gpFWSBP2DriverData->buffer, bufferLength);
- }
- else
- {
- //zzz Does this happen twice for synchronous commands?
- if( !gpFWSBP2DriverData->isWrite && gpFWSBP2DriverData->doubleBuffer ) {
- BlockMoveData( gpFWSBP2DriverData->dataBuffer, gpFWSBP2DriverData->buffer, bufferLength);
- }
- }
- #if VerifyWrites
- if( gpFWSBP2DriverData->needsVerify && gpFWSBP2DriverData->command[0] == 0x2a) {
-
- // Read data for comparison
- gpFWSBP2DriverData->whatWasWritten = (UInt8 *)gpFWSBP2DriverData->buffer;
- SBP2DoReadWriteBlocks( false, gpFWSBP2DriverData->count, gpFWSBP2DriverData->sector, (char *)gpFWSBP2DriverData->verifyBuffer, false);
- break;
- }
-
- if( gpFWSBP2DriverData->needsVerify && gpFWSBP2DriverData->command[0] != 0x2a ) {
-
- // Do the comparison
- for( x = 0; x < bufferLength; x++ ) {
-
- if( gpFWSBP2DriverData->whatWasWritten[x] != gpFWSBP2DriverData->verifyBuffer[x] ) {
- sprintf (debugStr, "pFWSBP2DiskDriver: Data mismatch! Written: %lx, Read: %lx, Offset %lx",
- (long) gpFWSBP2DriverData->whatWasWritten,
- (long) gpFWSBP2DriverData->verifyBuffer,
- (long) x);
- DebugStr ((ConstStr255Param) c2pstr (debugStr));
- break;
- }
- }
- gpFWSBP2DriverData->needsVerify = false;
- }
- #endif
-
- if( gpFWSBP2DriverData->xferLeft ) {
- SBP2DoReadWriteBlocks( gpFWSBP2DriverData->isWrite, gpFWSBP2DriverData->xferLeft, gpFWSBP2DriverData->next_block, gpFWSBP2DriverData->next_buffer, false);
- break;
- }
-
- gpFWSBP2DriverData->dce->dCtlPosition += (gpFWSBP2DriverData->ioPB->ioActCount = gpFWSBP2DriverData->ioPB->ioReqCount);
- gpFWSBP2DriverData->ioPending = false;
- IOCommandIsComplete (gpFWSBP2DriverData->ioCommandID, noErr);
- break;
- }
- }
-
- // If we got this far something bad happened so we should retry the current command
- if( gpFWSBP2DriverData->retriesLeft-- ) {
- SBP2DoReadWriteBlocks( gpFWSBP2DriverData->isWrite, gpFWSBP2DriverData->count, gpFWSBP2DriverData->sector, gpFWSBP2DriverData->buffer, false);
- }
- else {
- gpFWSBP2DriverData->ioPending = false;
- IOCommandIsComplete (gpFWSBP2DriverData->ioCommandID, ioErr);
- }
- break;
-
- case kSBP2NormalCommandReset:
- // Not much to do here. We'll retry when we get reconnectComplete notification.
- break;
-
- case kSBP2NormalCommandTimeout:
- // Fetch agent never sent us status.
-
- #if needLUNReset
- // Some SBP 2 devices have trouble recovering from error conditions. Preferably we would
- // reset the FA but some devices need to be kicked harder than others.
-
- if (gpFWSBP2DriverData->lunResetBusy)
- {
- gpFWSBP2DriverData->lunResetAgain = true;
- }
- else
- {
- gpFWSBP2DriverData->lunResetBusy = true;
- FWSBP2Manage( gpFWSBP2DriverData->fwLUNReset_ID);
- }
- return(noErr);
- #else
- // Fetch agent never sent us status. Try resetting it. We'll retry from the completionProc
- status = FWSetAsynchCommandParams
- (gpFWSBP2DriverData->fwAGENT_RESET_ID,
- 0, // generation - ignored
- gpFWSBP2DriverData->fetchAgent.addressHi, // addr from login response
- gpFWSBP2DriverData->fetchAgent.addressLo + 4, // + 4 to get AGENT_RESET
- (Ptr) gpFWSBP2DriverData, // any valid pointer will do
- 4, // quadlet write
- 0, // max payload - ignored
- 8, // max retries
- 0); // no flags
-
- // Reset agent
- if (status == noErr)
- {
- FWWrite (gpFWSBP2DriverData->fwAGENT_RESET_ID);
- return(noErr);
- }
- #endif
- break;
-
- case kSBP2UnsolicitedStatus:
- default:
- //DebugStr("\pUnsolicited status of some sort");
- break;
- }
- }
-
- completedOrb = pFWClientSBP2NotifyParams->fwCommandObjectID;
-
- if( completedOrb == gpFWSBP2DriverData->orbID[kImmedORB] ) {
- gpFWSBP2DriverData->immedStatus = cmdStatus;
- }
-
- return( compStatus );
-
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // SBPUnsolicitedStatusNotify
- //
- // This routine is called when an unsolicited status is received.
- //
-
- static OSStatus SBPUnsolicitedStatusNotify(
- FWClientSBP2NotifyParamsPtr pFWClientSBP2NotifyParams,
- UInt32 *pCommandAcceptance)
- {
- // Should now reset the Unsolocited Status Enabler - or else we'll never get any more.
- // This driver just receives one to prove that it can be done.
-
- *pCommandAcceptance = kFWClientCommandAcceptNoMore;
- return FWClientCommandIsComplete (pFWClientSBP2NotifyParams->fwClientInterfaceParams.fwClientCommandID, 0);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // SBP2Control
- //
- // Mass storage control routine.
- //
-
- static OSStatus SBP2Control(
- AddressSpaceID addressSpaceID,
- IOCommandID ioCommandID,
- IOCommandContents ioCommandContents,
- IOCommandKind ioCommandKind)
- {
- OSStatus status = noErr;
-
- switch (((CntrlParam *) ioCommandContents.pb)->csCode)
- {
- case 5 : // verifyTheDisc
- break;
-
- case 6 : // formatTheDisc
- break;
-
- case 21 : // getDriveIcon [HD]
- case 22 : // getMediaIcon [HD]
- *((UInt32 *) &(((CntrlParam *) ioCommandContents.pb)->csParam[0])) =
- (UInt32) (staticIconData);
- break;
-
- case 7 : // ejectTheDisc
- status = noErr;
- gpFWSBP2DriverData->gotEject = true;
- // Spin down the drive...
- SBP2Logout();
- break;
- case 23 : // driveInfo [HD]
- case 70 : // setPowerMode [HD]
- // Friendly drivers spin their disks down here.
- default :
- status = controlErr;
- break;
- }
-
- // We're complete.
- if (ioCommandKind == kImmediateIOCommandKind)
- return (status);
- else
- return (IOCommandIsComplete (ioCommandID, status));
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // SBP2Status
- //
- // Mass storage status routine.
- //
-
- static OSStatus SBP2Status(
- AddressSpaceID addressSpaceID,
- IOCommandID ioCommandID,
- IOCommandContents ioCommandContents,
- IOCommandKind ioCommandKind)
- {
- OSStatus status = noErr;
- DriverGestaltParam * gestaltPtr;
-
- switch (((CntrlParam *) ioCommandContents.pb)->csCode)
- {
- case kDriverGestaltCode:
- gestaltPtr = (DriverGestaltParam*)ioCommandContents.pb;
- switch(gestaltPtr->driverGestaltSelector)
- {
- case kdgSync:
- GetDriverGestaltSyncResponse(gestaltPtr)->behavesSynchronously = false;
- break;
-
- case kdgDeviceType:
- GetDriverGestaltDevTResponse(gestaltPtr)->deviceType = kdgDiskType;
- break;
-
- case kdgInterface:
- GetDriverGestaltIntfResponse(gestaltPtr)->interfaceType = kdgFireWireIntf;
- break;
-
- case kdgVersion:
- *GetDriverGestaltVersionResponse(gestaltPtr) = gFWDiskVersion;
- break;
-
- case kdgBoot:
- // Need to figure out what to do with this. !!! Vers 3.0
- break;
-
- case kdgVMOptions:
- // Don't let VM use this disk for a backing store.
- GetDriverGestaltVMOptionsResponse(gestaltPtr)->vmOptions = kAllowVMNoneMask;
- break;
-
- case kdgFlush:
- // May be important if your device has a write cache!
- GetDriverGestaltFlushResponse(gestaltPtr)->canFlush = false;
- GetDriverGestaltFlushResponse(gestaltPtr)->needsFlush = false;
- break;
-
- default:
- status = statusErr;
- break;
- }
- break;
- case kDriveStatus: // Do we care? Maybe for locked volumes
- BlockMove(&gpFWSBP2DriverData->driveStatus,&((CntrlParam *) ioCommandContents.pb)->csParam[0], sizeof(DrvSts));
- break;
- default :
- status = statusErr;
- break;
- }
-
- // We're complete.
- if (ioCommandKind == kImmediateIOCommandKind)
- return (status);
- else
- return (IOCommandIsComplete (ioCommandID, status));
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // SBP2CalculateMediaSize
- //
- // This routine performs a mode sense to calculate the media size
- // This routine makes only synchronous calls, so it must be called only at task
- // level.
- //
-
- static OSStatus SBP2CalculateMediaSize( void )
- {
- FWCommandObjectID orbID;
- FWAddress buffers[1];
- UInt32 lengths[1];
- char buffer[256];
- #define usesModeSense10 0
- #if usesModeSense10
- UInt8 command[12] = {0x5a, 0x08, 0x3e, 0, 0, 0, 0, 0, 0xff, 0, 0, 0};
- #else
- UInt8 command[12] = {0x25, 0, 0x00, 0, 0x00, 0, 0, 0, 0, 0, 0, 0};
- //UInt8 command[12] = {0x1a, 0, 0x3e, 0, 0x7f, 0, 0, 0, 0, 0, 0, 0};
- #endif
- OSStatus status;
-
- // !!! Comment this out if your drive supports Read Capacity
- //gpFWSBP2DriverData->totalBlocks = 0x200000;
- //return noErr;
-
- orbID = gpFWSBP2DriverData->orbID[kImmedORB]; // Immediate ORB
-
- // Prepare the ORB.
-
- buffers[0].addressHi = 0;
- buffers[0].addressLo = (UInt32) buffer;
- lengths[0] = 0x08;
- status = FWSetSBP2NormalCommandBuffers (orbID, 1, buffers, lengths);
-
- if (status == noErr)
- status = FWSetSBP2NormalCommandCommand (orbID, (Ptr) command, 12);
-
- if (status == noErr)
- status = FWSetSBP2NormalCommandTimeout (orbID, durationMillisecond * 1000);
-
- if (status == noErr)
- status = FWSetSBP2NormalCommandFlags (orbID,
- kSBP2CommandTransferDataFromTarget |
- kSBP2CommandCompleteNotify |
- kSBP2CommandImmediate |
- kSBP2CommandNormalORB);
-
- if (status == noErr)
- status = FWSetFWCommandFlags (orbID, kFWCommandSyncFlag);
-
- *(long*)&buffer[0] = 0;
-
- gpFWSBP2DriverData->immedStatus = ioInProgress; // Remember we're busy with this guy
-
- if (status == noErr)
- status = FWAppendSBP2Command (orbID);
-
- // The Append command was synchronous. When it returns, the command has been
- // appended to the target. But the target probably has not executed the command yet.
-
- if (status == noErr)
- {
- // Remember kiddies - don't do this at interrupt time!
- while( gpFWSBP2DriverData->immedStatus == ioInProgress )
- ;
-
- // Really need to try and reset the drive here but I'm not feeling up to it at the moment.
- // Perhaps a LogicalUnitReset might be in order...
-
- if( *(long*)&buffer[0] == 0 )
- return( ioErr );
-
- gpFWSBP2DriverData->totalBlocks = *(long*)&buffer[0] - 1;
- }
- else
- return( ioErr );
-
- return noErr;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // SBP2TUR
- //
- // Some drives need this
- //
-
- static OSStatus SBP2TUR( Boolean immediate )
- {
- FWCommandObjectID orbID;
- UInt8 * command;
- OSStatus status;
-
-
- if( immediate )
- orbID = orbID = gpFWSBP2DriverData->orbID[kImmedORB];
- else {
- orbID = gpFWSBP2DriverData->orbID[gpFWSBP2DriverData->currentORB];
-
- // Switch to the other ORB for next transaction
- gpFWSBP2DriverData->currentORB = ( gpFWSBP2DriverData->currentORB ? 0 : 1);
- }
-
- command = &gpFWSBP2DriverData->command[0];
-
- command[0] = 0x00; // TUR
- command[1] = 0;
- command[2] = 0;
- command[3] = 0;
- command[4] = 0;
- command[5] = 0;
- command[6] = 0;
- command[7] = 0;
- command[8] = 0;
- command[9] = 0;
- command[10] = 0;
- command[11] = 0;
-
- // Prepare the ORB.
-
- gpFWSBP2DriverData->buffers[0].addressHi = 0;
- gpFWSBP2DriverData->buffers[0].addressLo = (UInt32) gpFWSBP2DriverData->aBuffer;
- gpFWSBP2DriverData->lengths[0] = 0;
- FWSetSBP2NormalCommandBuffers (orbID, 0, gpFWSBP2DriverData->buffers, gpFWSBP2DriverData->lengths);
-
- status = FWSetSBP2NormalCommandCommand (orbID, (Ptr) command, 12);
-
- if (status == noErr)
- status = FWSetSBP2NormalCommandTimeout (orbID, durationMillisecond * 5000);
-
- if (status == noErr)
- status = FWSetSBP2NormalCommandFlags (orbID,
- kSBP2CommandCompleteNotify |
- kSBP2CommandImmediate |
- kSBP2CommandNormalORB);
-
- if( immediate ) {
- if (status == noErr)
- status = FWSetFWCommandFlags (orbID, kFWCommandSyncFlag);
- }
- else {
- if (status == noErr)
- status = FWSetFWCommandFlags (orbID, 0);
- }
-
- gpFWSBP2DriverData->immedStatus = ioInProgress; // Remember we're busy with this guy
-
- if (status == noErr) {
- status = FWAppendSBP2Command (orbID);
- //if( status )
- // DebugStr("\pFailed Append");
- }
-
- // The Append command was synchronous. When it returns, the command has been
- // appended to the target. But the target probably has not executed the command yet.
-
- if( (status == noErr) && immediate )
- {
- // Wait for completion
- // Remember kiddies - don't do this at interrupt time!
- while( gpFWSBP2DriverData->immedStatus == ioInProgress )
- ;
- status = gpFWSBP2DriverData->immedStatus;
- }
-
- if( (status == noErr) && !immediate ) {
- return( ioInProgress );
- }
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // ResetFACompletionProc
- //
- void
- ResetFACompletionProc(
- FWCommandObjectID fwCommandObjectID,
- OSStatus commandStatus,
- UInt32 completionProcData)
- {
- // Had to reset the fetch agent. If doing an IO the restart it. Otherwise report
- // and error (was an immediate or utility command).
- if( gpFWSBP2DriverData->ioPending ) {
- if( gpFWSBP2DriverData->retriesLeft-- ) {
- SBP2DoReadWriteBlocks( gpFWSBP2DriverData->isWrite, gpFWSBP2DriverData->count, gpFWSBP2DriverData->sector, gpFWSBP2DriverData->buffer, false);
- }
- else {
- gpFWSBP2DriverData->ioPending = false;
- IOCommandIsComplete (gpFWSBP2DriverData->ioCommandID, ioErr);
- }
- }
- else {
- gpFWSBP2DriverData->immedStatus = -1; // If we had to reset the fetch agent we got an error...
- }
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // BusyTimeoutCompletionProc
- //
- void
- BusyTimeoutCompletionProc(
- FWCommandObjectID fwCommandObjectID,
- OSStatus commandStatus,
- UInt32 completionProcData)
- {
- gpFWSBP2DriverData->busyTimeoutCommandBusy = false;
-
- // We may have logged in again but weren't able to call this command
- // because it was still busy. If so, start it up again.
-
- if (gpFWSBP2DriverData->busyTimeoutAgain)
- {
- gpFWSBP2DriverData->busyTimeoutAgain = false;
-
- if (FWWrite (gpFWSBP2DriverData->busyTimeoutCommandID) == noErr)
- gpFWSBP2DriverData->busyTimeoutCommandBusy = true;
- }
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // LoginCompletionProc
- //
- void
- LoginCompletionProc(
- FWCommandObjectID fwCommandObjectID,
- OSStatus commandStatus,
- UInt32 completionProcData)
- {
- gpFWSBP2DriverData->loginObjBusy = false;
-
- // If this is an attempt to clear an error condition - try logging in again
- if( gpFWSBP2DriverData->reLogin ) {
- gpFWSBP2DriverData->reLogin = false;
- FWSBP2Login (gpFWSBP2DriverData->loginCommandID);
- }
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // ManageCompletionProc
- //
- void
- ManageCompletionProc(
- FWCommandObjectID fwCommandObjectID,
- OSStatus commandStatus,
- UInt32 completionProcData)
- {
- OSStatus status;
-
- if (gpFWSBP2DriverData->lunResetAgain)
- {
- gpFWSBP2DriverData->lunResetAgain = false;
- FWSBP2Manage (gpFWSBP2DriverData->fwLUNReset_ID);
- }
- else
- {
- gpFWSBP2DriverData->lunResetBusy = false;
-
- status = FWSetAsynchCommandParams
- (gpFWSBP2DriverData->fwAGENT_RESET_ID,
- 0, // generation - ignored
- gpFWSBP2DriverData->fetchAgent.addressHi, // addr from login response
- gpFWSBP2DriverData->fetchAgent.addressLo + 4, // + 4 to get AGENT_RESET
- (Ptr) gpFWSBP2DriverData, // any valid pointer will do
- 4, // quadlet write
- 0, // max payload - ignored
- 8, // max retries
- 0); // no flags
-
- // Reset agent
- if (status == noErr)
- {
- FWWrite (gpFWSBP2DriverData->fwAGENT_RESET_ID);
- }
- }
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // ReconnectReadCompletionProc
- //
- void
- ReconnectReadCompletionProc(
- FWCommandObjectID fwCommandObjectID,
- OSStatus commandStatus,
- UInt32 completionProcData)
- {
- UInt32 deviceFlags;
- OSStatus status;
-
- if( !commandStatus ) {
- // This seems to happen if we get replugged after being unmounted, so we
- // need to set the CardBus eject prevention bit again.
-
- status = FWGetFWDeviceFlags ((FWReferenceID) gpFWSBP2DriverData->fwDriverID, &deviceFlags);
-
- deviceFlags |= kFWDeviceDoNotEjectCardBus;
-
- if (status == noErr)
- status = FWSetFWDeviceFlags ((FWReferenceID) gpFWSBP2DriverData->fwDriverID, deviceFlags);
-
- // Login again
- if (status == noErr)
- status = FWSBP2Login (gpFWSBP2DriverData->loginCommandID);
- }
- else
- gpFWSBP2DriverData->loginObjBusy = false;
-
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // ReplugCompletionProc
- //
- void
- ReplugCompletionProc(
- FWCommandObjectID fwCommandObjectID,
- OSStatus commandStatus,
- UInt32 completionProcData)
- {
- gpFWSBP2DriverData->wait4Replug = false;
- if( !commandStatus ) {
- // We could just log back into the drive again here but I've found its better to rely
- // on the look for the device after reset notification which will keep functioning even
- // after the user does a Command-. This way if the user realizes they made a mistake and
- // plug the drive back in we'll see it and login correctly.
- gpFWSBP2DriverData->returnDiskErr = false;
-
- // Go look for the drive and login if necessary.
- // Note that this guy is protected by a semaphore so that we won't try to use
- // either fwReplugID or loginCommandID more than once.
- FWSBPLookForDrive();
- }
- else {
- // return ioErr for our pending command and all subsequent commands
- if( gpFWSBP2DriverData->ioPending )
- IOCommandIsComplete (gpFWSBP2DriverData->ioCommandID, ioErr);
- gpFWSBP2DriverData->returnDiskErr = true;
-
- }
-
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // FWSBPLookForDrive
- //
- // Starts a Read, Login, Retry thread for our drive. Used after a reset or if
- // we somehow got ORB status while not logged in.
- //
- static void FWSBPLookForDrive( void )
- {
- OSStatus status = noErr;
-
- if( gpFWSBP2DriverData->wait4Replug )
- return; // Waiting for FSL to tell us what to do
-
- if( !gpFWSBP2DriverData->loggedIn && ! gpFWSBP2DriverData->reconnecting ) {
-
- if( CompareAndSwap( false, true, (unsigned long *) &gpFWSBP2DriverData->loginObjBusy ) ) {
-
- // We've been disconnected from our device and we need to know
- // whether it came back (as a result of this reset or re-plug notification.
- // Seems like the easiest way is to try a read from the device's CSR ROM.
- // If it works we can try to login and resume any command we had pending.
-
- status = FWSetAsynchCommandParams
- (gpFWSBP2DriverData->fwReconnectID,
- 0,
- 0xffff,
- 0xf0000400,
- (Ptr) &gpFWSBP2DriverData->bitBucket, // Actual data doesn't matter
- 4, // length of params
- 4, // max payload
- 4, // max retries
- 0); //
-
- if (status == noErr)
- {
- status = FWRead (gpFWSBP2DriverData->fwReconnectID);
-
- }
-
- if( status ) {
- gpFWSBP2DriverData->loginObjBusy = false;
- }
-
- }
- }
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // FWSBPResetNotify
- //
-
- static OSStatus FWSBPResetNotify(
- FWClientInterfaceParamsPtr pFWClientInterfaceParams,
- UInt32 *pCommandAcceptance)
- {
-
- FWSBPLookForDrive();
-
- // Complete FireWire client command.
- FWClientCommandIsComplete (pFWClientInterfaceParams->fwClientCommandID, noErr);
-
- // Return command acceptance.
- //zzz is this the right way? If we've completed the command, we can accept more.
- *pCommandAcceptance = kFWClientCommandAcceptNoMore;
-
- return noErr;
- }
-
-
- ///////////////////////////////////////////////
- //
- // Set the BUSY_TIMEOUT register in the drive.
- // This all runs at task level during the install.
- //
-
- static OSStatus SetBUSY_TIMEOUT (void)
- {
- FWCommandObjectID commandID;
- UInt32 busyTimeout;
- OSStatus allocStatus;
- OSStatus status = noErr;
-
- // Prepare a command object to quadlet read/write the BUSY_TIMEOUT register at 0x210.
-
- allocStatus = status = FWAllocateAsynchCommandObject (&commandID);
-
- if (status == noErr)
- status = FWSetFWCommandParams (commandID,
- gpFWSBP2DriverData->fwDriverID,
- kFWCommandSyncFlag, 0, 0);
-
- if (status == noErr)
- status = FWSetAsynchCommandParams
- (commandID, 0, 0xffff, 0xf0000210, (Ptr) &busyTimeout, 4, 4, 8, 0);
-
- // Read old value, set our desired retry count, and write it back.
-
- if (status == noErr)
- status = FWRead (commandID);
-
- if (status == noErr)
- {
- busyTimeout &= 0xfffffff0; // Preserve other bits
- busyTimeout |= 0x0000000f; // Set retry count to 15
-
- gpFWSBP2DriverData->busyTimeout = busyTimeout;
-
- status = FWWrite (commandID);
- }
-
- if (allocStatus == noErr)
- FWDeallocateFWCommandObject (commandID);
-
- return status;
- }
-
-
-
-